package com.lt.flashcard.view;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.impl.PageImpl;
import org.zkoss.zk.ui.metainfo.ComponentInfo;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.A;
import org.zkoss.zul.Include;
import org.zkoss.zul.Textbox;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Tag;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.TagService;

/**
 * Controller for worldliststart page
 * @version 1.0
 * @author ocsen
 *
 */
public class WordlistStartCtrl extends SelectorComposer<Component> {

	private static final long serialVersionUID = 1L;
	@Wire
	Textbox txtFilter; //the filter box
	
	@Wire
	Include ctnWordlist;
	
	@Wire
	A sMostView;
	@Wire
	A sMostRate;
	@Wire
	A sNewest;
	@Wire
	Textbox chkValues;
	
	private int curpage = 0;
	private int total = 0;
	private static final int PAGE_SIZE = 15;
	
	@Override
	public ComponentInfo doBeforeCompose(Page page, Component parent, ComponentInfo compInfo) {
		buildResult(true);
		((PageImpl) page).addBeforeHeadTags(String.format("<base href='%s/' >", Utility.getContextPath()));
		return super.doBeforeCompose(page, parent, compInfo);
	}
	
	/**
	 * Return the tree of tag list
	 * @return
	 */
	private List<Tag> _treelist = null;
	public List<Tag> getCategoryList() {
		if(_treelist == null) {
			TagService srv = Repository.getInstance().getTagService();
			_treelist = srv.getRootAdminTagList();
			//add all and other
			Tag other = new Tag();
			other.setName(Labels.getLabel("wordlist.category_other"));
			_treelist.add(other);
		}
		return _treelist;
	}
	
	/**
	 * Select category to filter the list
	 */
	@Listen("onChange=.chkValues")
	public void onChangeCategory(Event event) {
		buildResult(true);
		ctnWordlist.invalidate();
	}
	
	@Listen("onClick=.sorter")
	public void onSort(Event event) {
		try {
			sMostRate.setSclass("sorter");
			sMostView.setSclass("sorter");
			sNewest.setSclass("sorter");
		}
		catch (Exception e) { }
		
		A target = (A) event.getTarget();
		if(target != null)
			target.setSclass("sorter active");
		buildResult(false);
		ctnWordlist.invalidate();
	}
	
	private List<FlashcardSet> lstFcs; //Store the result
	private void buildResult(boolean newSearch) {
		if(newSearch) {
			curpage = 0;
			doQueryToDatabase(true);
		}
		doQueryToDatabase(false);
	}
	
	public void doQueryToDatabase(boolean fetchTotal) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		Criteria crit = srv.createCriteria();
		String values = "";
		List<String> categories = new ArrayList<String>();
		if(chkValues != null){
			values = chkValues.getValue();
			if(values.length() > 0)
				values = values.substring(0, values.length()-1);
		}
		if(values.length() > 0)		
			categories = Arrays.asList(values.split(","));
		//filter by tag
		if(categories.size() > 0) {
			List<String> tags = new ArrayList<String>();
			boolean other = false;
			for(String cate : categories) {
				if(cate.equals(Labels.getLabel("wordlist.category_all"))){
					tags.clear();
					break;
				}
				if(cate.equals(Labels.getLabel("wordlist.category_other"))) {//other
					other = true;
					continue;
				}
				tags.add(cate);
			}
			if(tags.size() > 0 || other) {
				/*crit.add(Restrictions.isNotNull("tg.parent"));*/
				Disjunction d = Restrictions.disjunction();
				crit.createAlias("tags", "tg");
				if(other) {
					d.add(Restrictions.isEmpty("tags"));
					d.add(Restrictions.eq("tg.reserved", 0));
				}
				if(tags.size() > 0) {
					d.add(Restrictions.in("tg.name", tags));
				}
				crit.add(d);
			}
		}
		
		//do filter by search
		if(txtFilter != null && !Utility.isEmptyString(txtFilter.getValue()) && !txtFilter.getValue().equals("Điền từ khóa để tìm được list từ hoặc flashcard phù hợp với bạn")) {
			crit.add(Restrictions.like("name", txtFilter.getValue(), MatchMode.ANYWHERE));
		}
		
		//check for privacy
		if(Utility.isLogin()) {
			Long cid = Utility.getUser().getId();
			crit.add(Restrictions.not(Restrictions.like("deniedusersCache", "," + cid.toString() + ",", MatchMode.ANYWHERE)));
			crit.add(Restrictions.ne("privacy", FlashcardSet.PRIVACY_PRIVATE));
		}
		else {
			crit.add(Restrictions.eq("privacy", FlashcardSet.PRIVACY_PUBLIC));
		}
		
		crit.add(Restrictions.gt("totalflashcards", 10));
		crit.add(Restrictions.eq("readysale", (byte) 0));
		crit.add(Restrictions.eq("admin", FlashcardSet.ADMIN_NO));
		crit.add(Restrictions.or(Restrictions.eq("originalflashcardsetCache", ""), Restrictions.ne("image", "")));
		crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		
		if(fetchTotal) {
			crit.setProjection(Projections.rowCount());
			total = (Integer) crit.uniqueResult();
		}
		else {
			if(currentSorter.equals("sMostView"))
				crit.addOrder(Order.desc("viewCount"));
			else if(currentSorter.equals("sMostRate"))
				crit.addOrder(Order.desc("voteResult"));
			else if(currentSorter.equals("sNewest"))
				crit.addOrder(Order.desc("created"));
			else {
				crit.addOrder(Order.desc("created"));
			}
			
			crit.setFirstResult(curpage * PAGE_SIZE);
			crit.setMaxResults(PAGE_SIZE);
			lstFcs = crit.list();
		}
		/*if(Utility.isLogin()) {
			AAService asrv = Repository.getInstance().getAAService();
			for(FlashcardSet fcs : lstFcs) {
				if(!asrv.checkAccess(fcs))
					lstFcs.remove(fcs);
			}
		}*/
	}

	/**
	 * Do the search and filters
	 * @return
	 */
	public List<FlashcardSet> getLstFlashcardSet() {
		return lstFcs == null ? new ArrayList<FlashcardSet>() : lstFcs;
	}
	
	@Listen("onClick=#btnFilter; onOK=#txtFilter")
	public void doFilter() {
		buildResult(true);
		ctnWordlist.invalidate();
	}
	
	/**
	 * Do sorter
	 * @param sorter
	 */
	private String currentSorter = "";
	public void updateSorter(String sorter) {
		currentSorter = sorter;
		ctnWordlist.setDynamicProperty("sorter", currentSorter);
		this.curpage = 0;
		buildResult(false);
		ctnWordlist.invalidate();
	}
	
	public void updatePaging(int page) {
		this.curpage = page;
		buildResult(false);
		ctnWordlist.invalidate();
	}

	/**
	 * @return the curpage
	 */
	public int getCurpage() {
		return curpage;
	}

	/**
	 * @param curpage the curpage to set
	 */
	public void setCurpage(int curpage) {
		this.curpage = curpage;
	}

	/**
	 * @return the total
	 */
	public int getTotal() {
		return total;
	}

	/**
	 * @param total the total to set
	 */
	public void setTotal(int total) {
		this.total = total;
	}
}